﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Net;
using System.Net.Sockets;
using System.Text;
using System.Threading.Tasks;

namespace MyNetwork
{
    public class ClientSocketTcp
    {
        public event Action<string> Received;
        public event Action<string> Closed;
        public bool Connected
        {
            get
            {
                if (connecting == true || sock == null) return false;
                return sock.Connected;
            }
        }

        public ClientSocketTcp()
        {
        }

        public string Key = "";
        public void Attach(Socket sock,string ip, int port)
        {
            connecting = false;
            _ip = ip;
            _port = port;
            Key = _ip + ":" + _port.ToString();
            this.sock = sock;

            Array.Clear(recv_buff, 0, recv_buff.Length);
            //for (int i = 0; i < count; i++)recv_buff[i] = 0;
            sock.BeginReceive(recv_buff, 0, len_buf, SocketFlags.None, ReceiveCallBack, this);
        }

        private Socket sock;
        private bool connecting = false;
        private byte[] recv_buff = new byte[1024 * 10 + 4];
        private string last_msg = "";
        private int len_buf = 1024 * 10;
        public string IP
        {
            get { return _ip; }
            set { _ip = value; }
        }
        private string _ip = "192.168.1.13";
        public int Port
        {
            get { return _port; }
            set { _port = value; }
        }
        private int _port = 12334;

        public void Connect()
        {
            Connect(_ip, _port);
        }

        public void Close()
        {
            try
            {
                if (Closed != null) Closed(Key);
                if (sock != null) sock.Close();
                lock (this) connecting = false;
                sock = null;
            }
            catch (Exception ex)
            {
                System.Diagnostics.Debug.WriteLine("ClientSocketTcp.Close " + ex.Message);
            }
        }

        public void Connect(string ip, int port)
        {
            if (connecting) return;
            lock (this) connecting = true;

            IPAddress ipAddress = null;
            try
            {
                ipAddress = IPAddress.Parse(ip);
            }
            catch (Exception)
            {
                throw new Exception("ip地址格式不正确，请使用正确的ip地址！");
            }

            try
            {
                _ip = ip;
                _port = port;
                last_msg = "";
                sock = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
                sock.NoDelay = true;
                sock.BeginConnect(ipAddress, port, ConnectCallBack, this);
            }
            catch (Exception ex)
            {
                System.Diagnostics.Debug.WriteLine("Failed to BeginConnect " + ex.Message);
                Close();
            }
        }
        public bool Send(string cmd)
        {
            try
            {
                lock (this)
                {
                    Byte[] sendBytes = Encoding.UTF8.GetBytes(cmd);
                    sock.Send(sendBytes, 0, sendBytes.Length, SocketFlags.None);
                }
            }
            catch (Exception ex)
            {
                Close();
                System.Diagnostics.Debug.WriteLine("CameraCmd.Send {0}  {1}", cmd, ex);
                return false;
            }
            return true;
        }

        private void ConnectCallBack(IAsyncResult ar)
        {
            try
            {
                if (sock == null)
                {
                    lock (this) connecting = false;
                    return;
                }
                //            if(ar.CompletedSynchronously==false)
                //{
                //                lock (this) connecting = false;
                //                return;
                //}
                sock.EndConnect(ar);

                if (ar.IsCompleted)
                {
                    if (sock.Connected)
                    {
                        sock.BeginReceive(recv_buff, 0, len_buf, SocketFlags.None, ReceiveCallBack, this);
                    }
                    lock (this) connecting = false;
                }
                else
                {
                    Close();
                }
            }
            catch (Exception ex)
            {
                System.Diagnostics.Debug.WriteLine("ConnectCallBack  " + ex.Message);
                Close();
            }
        }

        private void ReceiveCallBack(IAsyncResult ar)
        {
            int count = -1;
            try
            {
                if (sock == null)
                {
                    System.Diagnostics.Debug.WriteLine("sock == null");
                    return;
                }
                if (sock.Connected == false)
                {
                    System.Diagnostics.Debug.WriteLine("Connected == null");
                    Close();
                    return;
                }

                count = sock.EndReceive(ar);
                if (count > 0)
                {
                    string new_msg = Encoding.UTF8.GetString(recv_buff, 0, count);

                    Array.Clear(recv_buff, 0, recv_buff.Length);
                    //for (int i = 0; i < count; i++)recv_buff[i] = 0;


                    string msg = last_msg + new_msg;
                    int idx = 0;
                    for (idx = 0; idx >= 0;)
                    {
                        string msg_one = "";
                        idx = msg.IndexOf(":E#");
                        if (idx < 0)
                        {
                            last_msg = msg;
                            break;
                        }
                        else
                        {
                            msg_one = msg.Substring(0, idx + 3);
                            msg = msg.Substring(idx + 3);
                        }

                        if (!string.IsNullOrEmpty(msg_one))
                        {
                            System.Diagnostics.Debug.WriteLine("Receive:" + msg_one);
                            if (Received != null)
                            {
                                try
                                {
                                    Received(msg_one);//触发接收事件
                                }
                                catch (Exception ex)
                                {
                                    System.Diagnostics.Debug.WriteLine("Received " + ex.Message);
                                }
                            }
                        }
                    }

                    sock.BeginReceive(recv_buff, 0, len_buf, SocketFlags.None, ReceiveCallBack, this);
                }
                else if (count <= 0)
                {
                    Close();
                    System.Diagnostics.Debug.WriteLine("CameraCmd ReceiveCallBack < 0 ");
                }
                else
                {
                    System.Diagnostics.Debug.WriteLine("CameraCmd ReceiveCallBack ==0 ");
                }
            }
            catch (Exception ex)
            {
                System.Diagnostics.Debug.WriteLine("CameraCmd callback_receive  {0}", ex);
                Close();
            }
        }

    }
}
